﻿using System;

namespace ServerBase.Base
{
    public class ByteArray
    {
        /// <summary>
        /// Byte数组的默认大小 = 1024
        /// </summary>
        public const int DEFAULT_SIZE = 1024;
        /// <summary>
        /// 存储数据的Byte数组（数据缓冲）
        /// </summary>
        public byte[] Bytes;
        /// <summary>
        /// （当前）读取数据的索引
        /// </summary>
        public int ReadIndex;
        /// <summary>
        /// （当前）写入数据的索引
        /// </summary>
        public int WriteIndex;
        /// <summary>
        /// 数组容量
        /// </summary>
        public int Capacity;
        /// <summary>
        /// 初始数组容量
        /// </summary>
        public int InitCapacity;
        /// <summary>
        /// 数据长度
        /// </summary>
        public int Length => WriteIndex - ReadIndex;
        /// <summary>
        /// 剩余数组空间长度
        /// </summary>
        public int Remain => Capacity - WriteIndex;

        public ByteArray(int size = DEFAULT_SIZE)
        {
            InitCapacity = size;
            Capacity = DEFAULT_SIZE;
            ReadIndex = 0;
            WriteIndex = 0;
            Bytes = new byte[Capacity];
        }


        /// <summary>
        /// 字节数组构造
        /// </summary>
        /// <param name="defaultBytes"></param>
        public ByteArray(byte[] defaultBytes)
        {
            Bytes = defaultBytes;
            Capacity = defaultBytes.Length;
            InitCapacity = defaultBytes.Length;
            ReadIndex = 0;
            WriteIndex = defaultBytes.Length;
        }

        /// <summary>
        /// 检测接收到的数据长度：若小于8，则移动数据到数组起始位置（复用byte数组）
        /// </summary>
        public void CheckAndMoveBytes()
        {
            //copy操作复杂度 o(n) ，只对小数据做 copy 操作
            //Length<8有两种情况：1，数据小；2，数组空间耗尽（Length==0）
            if (Length < 8)
            {
                MoveBytes();
            }
        }
        /// <summary>
        /// 移动数据（移动数据的复杂度为 o(n) ，所以对于大数据不宜copy操作）
        /// </summary>
        public void MoveBytes()
        {
            if (ReadIndex < 0) return;
            Array.Copy(Bytes, ReadIndex, Bytes, 0, Length);
            WriteIndex = Length;
            ReadIndex = 0;
        }
        /// <summary>
        /// 重设Byte数组大小
        /// </summary>
        public void ReSize(int newSize)
        {
            if (ReadIndex < 0) return;
            if (newSize < Capacity) return;
            if (newSize < InitCapacity) return;
            while (Capacity < newSize) Capacity *= 2;
            byte[] newBytes = new byte[Capacity];
            Array.Copy(Bytes, ReadIndex, newBytes, 0, Length);
            Bytes = newBytes;
            WriteIndex = Length;
            ReadIndex = 0;//重新开始读
        }

        /// <summary>
        /// 写入数据
        /// </summary>
        /// <param name="bs"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public int Write(byte[] bs, int offset, int count)
        {
            if (Remain < count)
            {
                ReSize(Length + count);
            }
            Array.Copy(bs, offset, Bytes, WriteIndex, count);
            WriteIndex += count;
            return count;
        }

        /// <summary>
        /// 读取数据
        /// </summary>
        /// <param name="bs"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public int Read(byte[] bs, int offset, int count)
        {
            count = Math.Min(count, Length);
            Array.Copy(Bytes, 0, bs, offset, count);
            ReadIndex += count;
            CheckAndMoveBytes();
            return count;
        }

        /// <summary>
        /// 从头部读取一个Int16
        /// </summary>
        /// <returns></returns>
        public short ReadInt16()
        {
            if (Length < 2) return 0;
            short ret = (short)(Bytes[1] << 8 | Bytes[0]);
            ReadIndex += 2;
            CheckAndMoveBytes();
            return ret;
        }

        /// <summary>
        /// 从头部读取一个Int32
        /// </summary>
        /// <returns></returns>
        public int ReadInt32()
        {
            if (Length < 4) return 0;
            int ret = Bytes[3] << 24 |
                                 Bytes[2] << 16 |
                                 Bytes[1] << 8 |
                                  Bytes[0];
            ReadIndex += 4;
            CheckAndMoveBytes();
            return ret;
        }

        public override string ToString()
        {
            return BitConverter.ToString(Bytes, ReadIndex, Length);
        }

        //打印调试信息（仅为调试）
        public string Debug()
        {
            return string.Format("readIdx({0}) writeIdx({1}) bytes({2})",
                ReadIndex,
                WriteIndex,
                BitConverter.ToString(Bytes, 0, Bytes.Length)
            );
        }

    }
}